/*
* Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef OHMW_INTERFACE_NAPI_NAPI_UTILS_H
#define OHMW_INTERFACE_NAPI_NAPI_UTILS_H

#include <napi/native_api.h>
#include <hilog/log.h>
#include <cstring>

namespace OHOS {
namespace OHMW_NAPI {
#define APP_LOG_DOMAIN 0x0001
#define APP_LOG_TAG "ohmw_napi"

#define CLOGI(...) ((void)OH_LOG_Print(LOG_APP, LOG_INFO, APP_LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
#define CLOGD(...) ((void)OH_LOG_Print(LOG_APP, LOG_DEBUG, APP_LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
#define CLOGW(...) ((void)OH_LOG_Print(LOG_APP, LOG_WARN, APP_LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
#define CLOGE(...) ((void)OH_LOG_Print(LOG_APP, LOG_ERROR, APP_LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))

#define NAPI_CHECK_STATUS(msg)                                                                                         \
    if (_status != napi_ok) {                                                                                          \
        CLOGE(msg);                                                                                                    \
        return NULL;                                                                                                   \
    }

#define NAPI_PACKAGE_BOOL(outputName, value)                                                                           \
    napi_value outputName = nullptr;                                                                                   \
    {                                                                                                                  \
        napi_status _status = napi_get_boolean(env, value, &outputName);                                               \
        NAPI_CHECK_STATUS("Failed to create boolean");                                                                 \
    }

#define NAPI_PACKAGE_INT32(outputName, value)                                                                          \
    napi_value outputName = nullptr;                                                                                   \
    {                                                                                                                  \
        napi_status _status = napi_create_int32(env, value, &outputName);                                              \
        NAPI_CHECK_STATUS("Failed to create int32");                                                                   \
    }

#define NAPI_PACKAGE_UINT32(outputName, value)                                                                         \
    napi_value outputName = nullptr;                                                                                   \
    {                                                                                                                  \
        napi_status _status = napi_create_uint32(env, value, &outputName);                                             \
        NAPI_CHECK_STATUS("Failed to create uint32");                                                                  \
    }

#define NAPI_PACKAGE_INT64(outputName, value)                                                                          \
    napi_value outputName = nullptr;                                                                                   \
    {                                                                                                                  \
        napi_status _status = napi_create_int64(env, value, &outputName);                                              \
        NAPI_CHECK_STATUS("Failed to create int64");                                                                   \
    }

#define NAPI_PACKAGE_UNDEFINED(outputName)                                                                             \
    napi_value outputName = nullptr;                                                                                   \
    {                                                                                                                  \
        napi_status _status = napi_get_undefined(env, &outputName);                                                    \
        NAPI_CHECK_STATUS("Failed to create undefined");                                                               \
    }

#define NAPI_PACKAGE_UINT8_ARRAY(outputName, data, len)                                                                \
    napi_value outputName = nullptr;                                                                                   \
    {                                                                                                                  \
        napi_value arrayBuffer;                                                                                        \
        void *buffer_data;                                                                                             \
        napi_status _status = napi_create_arraybuffer(env, len, &buffer_data, &arrayBuffer);                           \
        NAPI_CHECK_STATUS("Failed to create array buffer");                                                            \
        std::memcpy(buffer_data, data, len);                                                                           \
        _status = napi_create_typedarray(env, napi_uint8_array, len, arrayBuffer, 0, &outputName);                     \
        NAPI_CHECK_STATUS("Failed to create typed array");                                                             \
    }

#define NAPI_PACKAGE_STRING(outputName, data, len)                                                                     \
    napi_value outputName = nullptr;                                                                                   \
    {                                                                                                                  \
        napi_status _status = napi_create_string_utf8(env, data, len, &outputName);                                    \
        NAPI_CHECK_STATUS("napi_create_string_utf8 failed");                                                           \
    }

#define NAPI_PACKAGE_DOUBLE(outputName, value)                                                                         \
    napi_value outputName = nullptr;                                                                                   \
    {                                                                                                                  \
        napi_status _status = napi_create_double(env, value, &outputName);                                             \
        NAPI_CHECK_STATUS("Failed to create double");                                                                  \
    }

#define NAPI_CHECKOUT_ARGS0                                                                                            \
    napi_value thisVar = nullptr;                                                                                      \
    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);                                                  \

#define NAPI_CHECKOUT_ARGS(count)                                                                                      \
    napi_value thisVar = nullptr;                                                                                      \
    size_t argc = count;                                                                                               \
    napi_value args[count];                                                                                            \
    napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr);                                                       \
    if (argc < count) {                                                                                                \
        CLOGE("Invalid argument");                                                                                     \
        return nullptr;                                                                                                \
    }

#define NAPI_CHECKOUT_STRING(outputName, maxLength, napiValue)                                                         \
    std::string outputName;                                                                                            \
    {                                                                                                                  \
        char tmpBuffer[maxLength] = {0};                                                                               \
        size_t tmpLength = 0;                                                                                          \
        napi_get_value_string_utf8(env, napiValue, tmpBuffer, maxLength, &tmpLength);                                  \
        outputName = std::string(tmpBuffer, tmpLength);                                                                \
    }

#define NAPI_CHECKOUT_OBJECT(outputName, napiValue)                                                                   \
    napi_value outputName = nullptr;                                                                                   \
    {                                                                                                                  \
        napi_status _status = napi_get_value_object(env, napiValue, &outputName);                                       \
        NAPI_CHECK_STATUS("Failed to get object");                                                                     \
    }

#define NAPI_CHECKOUT_FUNCTION(outputName, napiValue)                                                                  \
    {                                                                                                                  \
        napi_valuetype valuetype;                                                                                      \
        napi_status _status = napi_typeof(env, napiValue, &valuetype);                                                              \
        NAPI_CHECK_STATUS("Failed to get function");                                                                   \
        if (valuetype != napi_function) {                                                                              \
            CLOGE("Argument must be a function");                                                                      \
            return nullptr;                                                                                            \
        }                                                                                                              \
    }                                                                                                                  \
    napi_value outputName = napiValue;

#define NAPI_CHECKOUT_UINT8_ARRAY(outputName, outputLength, napiValue)                                                 \
    uint8_t *outputName = nullptr;                                                                                     \
    size_t outputLength;                                                                                               \
    {                                                                                                                  \
        napi_typedarray_type type;                                                                                     \
        napi_status _status =                                                                                          \
            napi_get_typedarray_info(env, napiValue, &type, &outputLength, (void **)&outputName, NULL, NULL);          \
        if (_status != napi_ok || type != napi_uint8_array) {                                                          \
            napi_throw_type_error(env, NULL, "Argument must be a Uint8Array");                                         \
            return NULL;                                                                                               \
        }                                                                                                              \
    }

#define NAPI_CHECKOUT_BUFFER(outputName, outputLength, napiValue)                                                      \
    uint8_t *outputName = nullptr;                                                                                     \
    size_t outputLength;                                                                                               \
    {                                                                                                                  \
        napi_status _status = napi_get_buffer_info(env, napiValue, (void **)&outputName, &outputLength);               \
        NAPI_CHECK_STATUS("Failed to get buffer");                                                                     \
    }

#define NAPI_CHECKOUT_BOOL(outputName, napiValue)                                                                      \
    bool outputName;                                                                                                   \
    {                                                                                                                  \
        napi_status _status = napi_get_value_bool(env, napiValue, &outputName);                                         \
        NAPI_CHECK_STATUS("Failed to get bool");                                                                       \
    }

#define NAPI_CHECKOUT_INT32(outputName, napiValue)                                                                     \
    int32_t outputName;                                                                                                \
    {                                                                                                                  \
        napi_status _status = napi_get_value_int32(env, napiValue, &outputName);                                        \
        NAPI_CHECK_STATUS("Failed to get int32");                                                                      \
    }

#define NAPI_CHECKOUT_UINT32(outputName, napiValue)                                                                    \
    uint32_t outputName;                                                                                               \
    {                                                                                                                  \
        napi_status _status = napi_get_value_uint32(env, napiValue, &outputName);                                       \
        NAPI_CHECK_STATUS("Failed to get uint32");                                                                     \
    }

#define NAPI_CHECKOUT_INT64(outputName, napiValue)                                                                     \
    int64_t outputName;                                                                                                \
    {                                                                                                                  \
        napi_status _status = napi_get_value_int64(env, napiValue, &outputName);                                        \
        NAPI_CHECK_STATUS("Failed to get int64");                                                                     \
    }

#define NAPI_CHECKOUT_DOUBLE(outputName, napiValue)                                                                   \
    double outputName;                                                                                                \
    {                                                                                                                  \
        napi_status _status = napi_get_value_double(env, napiValue, &outputName);                                      \
        NAPI_CHECK_STATUS("Failed to get double");                                                                   \
    }

#define NAPI_GET_PROPERTY(obj, name, outputName)                                                                       \
    napi_value outputName = nullptr;                                                                                   \
    {                                                                                                                  \
        napi_status _status = napi_get_named_property(env, obj, name, &outputName);                                 \
    }

} // namespace OHMW_NAPI
} // namespace OHOS

#endif